package com.yuand.config;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author yuandong
 * @date 2021/4/17 10:29
 */
@Configuration
public class ShiroConfig {
    //需要配置三个核心对象

    //1.realm对象，自己定义
    @Bean  //交由spring管理
    public UserRealm userRealm( HashedCredentialsMatcher credentialsMatcher) {
        UserRealm userRealm = new UserRealm();
        userRealm.setCredentialsMatcher(credentialsMatcher);
        return userRealm;
    }

    //2.DefaultWebSecurManager   怎么将自定义的realm，传递给这个类呢，使用@Qualifier注解
    @Bean(name = "securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //关联自定义的realm
        securityManager.setRealm(userRealm);
        return securityManager;
    }

    //3.ShiroFilterFactoryBean
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
        //3.1设置安全管理器
        shiroFilter.setSecurityManager(defaultWebSecurityManager);
        shiroFilter.setLoginUrl("/login.html");
        //设置未授权访问的页面路径—当权限不足时显示此页面
        shiroFilter.setUnauthorizedUrl("/lesspermission.html");

        //3.2添加shiro的内置过滤器
        /**
         * anon: 无需认证就可访问
         * authc: 必须认证了才能访问
         * perms: 必须拥有某个资源的权限才能访问
         * roles: 必须拥有某个角色才能访问
         */
        Map<String, String> filterMap = new LinkedHashMap<>();

        //项目根目录无需拦截
        filterMap.put("/","anon");
        //注册页面及注册提交页面无需拦截
        filterMap.put("/register.html","anon");
        filterMap.put("/user/register","anon");
        //登录页面及登录提交页面无需拦截
        filterMap.put("/login.html","anon");
        filterMap.put("/user/login","anon");
        //测试百度地图不要拦截
        filterMap.put("/baiduMap.html","anon");
        //登录成功进入index页面
        filterMap.put("/**","authc");  //注意这里除了上面几种无需认证的请求，其它的任何请求都必须认证(登录)，那这里就会存在一种情况，比如张三认证了，但他可以通过url访问任何资源了，所以需要在后台controller加上shiro权限标签

        //filterMap.put("/user/add", "authc");
        //filterMap.put("/user/edit", "authc");

        shiroFilter.setFilterChainDefinitionMap(filterMap);

        return shiroFilter;
    }


    /**
     * 凭证匹配器
     * （由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了
     *  所以我们需要修改下doGetAuthenticationInfo中的代码;
     * ）
     * @return
     */
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher(){
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("md5");//散列算法:这里使用MD5算法;
        hashedCredentialsMatcher.setHashIterations(2);//散列的次数，比如散列两次，相当于 md5(md5(""));
        return hashedCredentialsMatcher;
    }


    /**
     * springboot对shiro注解的支持
     * @return
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        autoProxyCreator.setProxyTargetClass(true);
        //autoProxyCreator.setUsePrefix(true);
        return autoProxyCreator;
    }


    @Bean
    public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }


    /**
     * 在页面中支持shiro标签
     * @return
     */
    @Bean
    public ShiroDialect shiroDialect() {
        return new ShiroDialect();
    }


}
